#include "UI/DefaultUI.h"
#include "core/Configurator.h"
// #include "testing.h"

using namespace OBR;

int main(int argc, char const *argv[])
{

#ifdef OBR_TESTING_H
    testing();
#ifdef EXIT_AFTER_TEST
    return 0;
#endif
#endif

    // print status
    CUDAUtilities::printDeviceProp(0);

    // initialize factories
    Configurator::initProgram();

    // load scene from config
    Configurator configurator;
    if (argc == 1)
    {
        configurator = Configurator();
    }
    else
    {
        std::string config_file_path = "";
        for (size_t i = 1; i < argc; i++)
        {
            std::string arg = std::string(argv[i]);
            if (arg == "-config" && i < argc - 1)
            {
                config_file_path = std::string(argv[i + 1]);
            }
        }
        configurator = Configurator(config_file_path);
    }
    Scene sc = configurator.getScene();

    // setup scene
    sc.setupLaunchParams();
    sc.setupRenderer();
    sc.enable_accumulate = true;

    // render
    double fps = -1;
    int key = -1;
    while (key != 27)
    {
        double dt;

        auto t0 = std::chrono::steady_clock::now();
        sc.renderFrame();
        auto t1 = std::chrono::steady_clock::now();
        dt = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count() / 1e9;

        if (fps == -1)
        {
            fps = 1.0 / dt;
        }
        else
        {
            fps = fps * 0.9 + 1.0 / dt * 0.1;
        }
        char desc[128] = {};
        sprintf(desc, "fps: %.2f, total samples: %zu", fps, sc.acc_sample_cnt);

        DefaultUI::show(sc, "result", desc);
        key = cv::waitKey(10);
    }
    std::string save_path = std::string(PROJ_ROOT) + "/result.png";
    saveImageCV(sc.result, sc.params.width, sc.params.height, save_path);

    std::cout << "program ended" << std::endl;
    return 0;
}
